using System;
using System.Threading;

namespace ELS.Configuration
{
	/// <summary>
	/// The TimedLock structure marks a statement block as a critical section by 
	/// obtaining the mutual-exclusion lock for a given object, executing a statement block, 
	/// and then releasing the lock when disposed.
	/// </summary>
	/// <example> 
	/// <code>
	/// using ( new TimedLock ( objectToLock ) )
	/// {
	///		// your code goes here...
	/// }
	/// </code>
	/// </example>
	/// <remarks>
	/// The TimedLock structure implements the RAII pattern and abstracts the need for writing 
	/// a try,catch, finally blocks around a critical section.
	/// <p>The TimedLock uses a <see cref="System.Threading.Monitor"/>.<see cref="System.Threading.Monitor.TryEnter"/> instead of a 
	/// <see cref="System.Threading.Monitor"/>.<see cref="System.Threading.Monitor.Enter"/>
	/// to avoid scenarios where the code will block indefinitely (deadlock) because the monitor is unavailable. </p>
	/// <p>The default timeout to acquire an exclusive lock is 600000 milliseconds.</p>
	/// </remarks>
	public struct TimedLock : IDisposable
	{
		private object _object;

		/// <summary>
		/// Attempts to acquire an exclusive lock on the specified object.
		/// </summary>
		/// <param name="obj">The object on which to acquire the lock.</param>
		public TimedLock(object obj):this(obj, Constants.THREAD_TIMEOUT )
		{
		}

		/// <summary>
		/// Attempts to acquire an exclusive lock on the specified object.
		/// </summary>
		/// <param name="obj">The object on which to acquire the lock.</param>
		/// <param name="timeout">A <see cref=" System.TimeSpan"/> representing the amount of time to wait for the lock. </param>
		public TimedLock(object obj, TimeSpan timeout)
		{
			_object = obj;
			Monitor.TryEnter( obj, timeout);
		}

		/// <summary>
		/// Attempts to acquire an exclusive lock on the specified object.
		/// </summary>
		/// <param name="obj">The object on which to acquire the lock.</param>
		/// <param name="millisecondsTimeout">The number of milliseconds to wait for the lock.</param>
		public TimedLock(object obj, int millisecondsTimeout): this ( obj, new TimeSpan(0,0,0,0,millisecondsTimeout))
		{
		}

		#region IDisposable Members

		/// <summary>
		/// Releases the resources used by the TimedLock.
		/// </summary>
		public void Dispose()
		{
			if ( _object != null)
				Monitor.Exit( _object );
		}
		#endregion
	}
}
